package com.api.volunteer.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.api.volunteer.dto.AccessTokenDTO;
import com.api.volunteer.model.*;
import com.api.volunteer.repository.AccessTokenRepository;
import com.api.volunteer.repository.AccountRepository;
import com.api.volunteer.repository.UserRepository;
import com.api.volunteer.service.SubcribeMessageService;
import com.api.volunteer.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author 邹宇杰
 * @email 2901570623@qq.com
 * @date 2022/4/2 21:50
 */
@Service("subsribeMessageService")
public class SubsribeMessageServiceImpl implements SubcribeMessageService {

    @Autowired
    AccessTokenRepository accessTokenRepository;

    private String urlTemplate = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    private String sendTemplate = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s";

    @Value("${wx.appid}")
    private String appid;

    @Value("${wx.secret}")
    private String secret;

    @Autowired
    UserRepository userRepository;

    @Autowired
    AccountRepository accountRepository;

    @Autowired
    ThreadPoolTaskExecutor taskExecutor;

    @Value("${wx.audit.templateId}")
    private String auditTemplateId;

    @Value("${wx.sign.templateId}")
    private String signTemplateId;

    @Override
    public void sendAuditMessage(String openid) {

            RestTemplate restTemplate = new RestTemplate();

            AccessToken trueToken = getAccessToken.get();

            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));

            Map<String, Object> bodyMap = new HashMap<>(4);

            bodyMap.put("touser", openid);
            bodyMap.put("template_id", auditTemplateId);
            bodyMap.put("page", "index");

            UserEntity userEntityByOpenid = userRepository.findUserEntityByOpenid(openid);
            Account accountByOpenid = accountRepository.findAccountByOpenid(openid);

            System.out.println(accountByOpenid);

            Map<String, Object> dataMap = new HashMap<>(5);

            Map<String, Object> thing11Value = new HashMap<>(1);
            Map<String, Object> time12Value = new HashMap<>(1);
            Map<String, Object> time13Value = new HashMap<>(1);
            Map<String, Object> thing16Value = new HashMap<>(1);
            Map<String, Object> thing17Value = new HashMap<>(1);

            thing11Value.put("value", userEntityByOpenid.getNickName());
            time12Value.put("value", accountByOpenid.getEmployerName());
            time13Value.put("value", function.apply(accountByOpenid.getLastUpdateDate()));
            thing16Value.put("value", "志愿机构申请入驻");
            thing17Value.put("value", tranTo.apply(accountByOpenid.getStatus()));

            dataMap.put("thing11", thing11Value);
            dataMap.put("thing12", time12Value);
            dataMap.put("time13", time13Value);
            dataMap.put("thing16", thing16Value);
            dataMap.put("thing17", thing17Value);

            bodyMap.put("data", dataMap);

            taskExecutor.submit(()->{
                HttpEntity<Map<String, Object>> objectHttpEntity = new HttpEntity<>(bodyMap,httpHeaders);

                String sendUrl = String.format(sendTemplate, trueToken.getAccessToken());

                String s = restTemplate.postForObject(sendUrl, objectHttpEntity, String.class);

                System.out.println(s);
            });

    }

    @Override
    public void sendAuditSuccessMessage(String openid) {
        taskExecutor.submit(()->{
            RestTemplate restTemplate = new RestTemplate();

            AccessToken trueToken = getAccessToken.get();

            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));

            Map<String, Object> bodyMap = new HashMap<>(4);

            bodyMap.put("touser", openid);
            bodyMap.put("template_id", auditTemplateId);
            bodyMap.put("page", "index");

            UserEntity userEntityByOpenid = userRepository.findUserEntityByOpenid(openid);
            Account accountByOpenid = accountRepository.findAccountByOpenid(openid);


            Map<String, Object> dataMap = new HashMap<>(5);

            Map<String, Object> thing11Value = new HashMap<>(1);
            Map<String, Object> time12Value = new HashMap<>(1);
            Map<String, Object> time13Value = new HashMap<>(1);
            Map<String, Object> thing16Value = new HashMap<>(1);
            Map<String, Object> thing17Value = new HashMap<>(1);

            thing11Value.put("value", userEntityByOpenid.getNickName());
            time12Value.put("value", accountByOpenid.getEmployerName());
            time13Value.put("value", function.apply(accountByOpenid.getCreateDate()));
            thing16Value.put("value", "您的入驻申请已经通过");
            thing17Value.put("value", tranTo.apply(accountByOpenid.getStatus()));

            dataMap.put("thing11", thing11Value);
            dataMap.put("thing12", time12Value);
            dataMap.put("time13", time13Value);
            dataMap.put("thing16", thing16Value);
            dataMap.put("thing17", thing17Value);

            bodyMap.put("data", dataMap);

            HttpEntity<Map<String, Object>> objectHttpEntity = new HttpEntity<>(bodyMap,httpHeaders);

            String sendUrl = String.format(sendTemplate, trueToken.getAccessToken());

            String s = restTemplate.postForObject(sendUrl, objectHttpEntity, String.class);

            return new Result().put("message", s);
        });
    }

    @Override
    public void sendAuditFailMessage(String openid) {
            RestTemplate restTemplate = new RestTemplate();

            AccessToken trueToken = getAccessToken.get();

            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));

            Map<String, Object> bodyMap = new HashMap<>(4);

            bodyMap.put("touser", openid);
            bodyMap.put("template_id", auditTemplateId);
            bodyMap.put("page", "index");

            UserEntity userEntityByOpenid = userRepository.findUserEntityByOpenid(openid);
            Account accountByOpenid = accountRepository.findAccountByOpenid(openid);


            Map<String, Object> dataMap = new HashMap<>(5);

            Map<String, Object> thing11Value = new HashMap<>(1);
            Map<String, Object> time12Value = new HashMap<>(1);
            Map<String, Object> time13Value = new HashMap<>(1);
            Map<String, Object> thing16Value = new HashMap<>(1);
            Map<String, Object> thing17Value = new HashMap<>(1);

            thing11Value.put("value", userEntityByOpenid.getNickName());
            time12Value.put("value", accountByOpenid.getEmployerName());
            time13Value.put("value", function.apply(accountByOpenid.getCreateDate()));
            thing16Value.put("value", "您的入驻申请被驳回, 请重新提交表单");
            thing17Value.put("value", tranTo.apply(accountByOpenid.getStatus()));

            dataMap.put("thing11", thing11Value);
            dataMap.put("thing12", time12Value);
            dataMap.put("time13", time13Value);
            dataMap.put("thing16", thing16Value);
            dataMap.put("thing17", thing17Value);

            bodyMap.put("data", dataMap);

            taskExecutor.submit(()->{
                HttpEntity<Map<String, Object>> objectHttpEntity = new HttpEntity<>(bodyMap,httpHeaders);

                String sendUrl = String.format(sendTemplate, trueToken.getAccessToken());

                String s = restTemplate.postForObject(sendUrl, objectHttpEntity, String.class);
            });

    }

    @Override
    public void sendVolunteerMessage(List<VolunteerRecord> volunteerRecords) {
        RestTemplate restTemplate = new RestTemplate();

        AccessToken trueToken = getAccessToken.get();

         for (VolunteerRecord volunteerRecord : volunteerRecords) {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));

                Map<String, Object> bodyMap = new HashMap<>(4);

                bodyMap.put("touser", volunteerRecord.getOpenid());
                bodyMap.put("template_id", signTemplateId);
                bodyMap.put("page", "index");


                Map<String, Object> dataMap = new HashMap<>(5);

                Map<String, Object> thing2Value = new HashMap<>(1);
                Map<String, Object> time8Value = new HashMap<>(1);
                Map<String, Object> time9Value = new HashMap<>(1);
                Map<String, Object> thing10Value = new HashMap<>(1);
                Map<String, Object> thing11Value = new HashMap<>(1);

                thing2Value.put("value", "活动开始");
                time8Value.put("value", function.apply(volunteerRecord.getBeginDate()));
                time9Value.put("value", function.apply(volunteerRecord.getEndDate()));
                thing10Value.put("value", volunteerRecord.getAddress());
                thing11Value.put("value", "志愿活动已经开始了, 请注意参加");

                dataMap.put("thing2", thing2Value);
                dataMap.put("time8", time8Value);
                dataMap.put("time9", time9Value);
                dataMap.put("thing10", thing10Value);
                dataMap.put("thing11", thing11Value);

                bodyMap.put("data", dataMap);

                System.out.println(dataMap);

                taskExecutor.submit(()->{

                    HttpEntity<Map<String, Object>> objectHttpEntity = new HttpEntity<>(bodyMap,httpHeaders);

                    String sendUrl = String.format(sendTemplate, trueToken.getAccessToken());

                    String s = restTemplate.postForObject(sendUrl, objectHttpEntity, String.class);

                    System.out.println(s);
                });
         }
    }

    @Override
    public void sendReserveMessage(String openid, String volunteerId) {

    }

    @Override
    public void sendSignMessage(String volunteerId) {

    }



    private final Supplier<AccessToken> getAccessToken = (()->{
        RestTemplate restTemplate = new RestTemplate();

        AccessToken trueToken = null;

        String format = String.format(urlTemplate, appid, secret);


        trueToken = Optional.ofNullable(accessTokenRepository.findAccessTokenByTokenName("tokenName")).orElseGet(() -> {
            String response = restTemplate.getForObject(format, String.class);

            AccessTokenDTO accessTokenDTO = JSONObject.parseObject(response, AccessTokenDTO.class);

            AccessToken accessToken = new AccessToken();
            accessToken.setAccessToken(accessTokenDTO.getAccess_token());
            accessToken.setTokenName("tokenName");
            accessToken.setExpireTime(accessTokenDTO.getExpires_in());
            accessTokenRepository.save(accessToken);
            return accessToken;
        });

        if((System.currentTimeMillis() - trueToken.getLastUpdateDate().getTime())/1000 > trueToken.getExpireTime()){
            AccessToken accessToken = accessTokenRepository.findAccessTokenByTokenName("tokenName");
            String forObject = restTemplate.getForObject(format, String.class);

            AccessTokenDTO accessTokenDTO = JSONObject.parseObject(forObject, AccessTokenDTO.class);

            accessToken.setAccessToken(accessTokenDTO.getAccess_token());
            accessToken.setExpireTime(accessTokenDTO.getExpires_in());

            accessTokenRepository.save(accessToken);
        }
        return trueToken;
    });

    private final Function<Date, String> function = ((d)->{
        SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        String date = format.format(d);
        return date;
    });

    private final Function<Enum, String> tranTo = ((e)->{
        if(Objects.equals(e, Status.Auditing)){
            return "审核中";
        }else if (Objects.equals(e, Status.AuditSuccess)){
            return "审核成功";
        }else{
            return "审核失败";
        }
    });
}
